package net.ankao.job.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import net.ankao.framework.starter.base.common.AkPageable;
import net.ankao.framework.starter.base.exception.AkException;
import net.ankao.framework.starter.base.utils.CommonUtil;
import net.ankao.framework.starter.mybatis.plus.utils.AkPageableUtils;
import net.ankao.job.common.ClientJobManager;
import net.ankao.job.core.common.JobInfo;
import net.ankao.job.entity.AkApplication;
import net.ankao.job.entity.AkApplicationJob;
import net.ankao.job.entity.dto.JobListDTO;
import net.ankao.job.entity.dto.JobUpdateDTO;
import net.ankao.job.mapper.AkApplicationJobMapper;
import net.ankao.job.service.IAkApplicationJobService;
import net.ankao.job.utils.CronUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * Job表 服务实现类
 * </p>
 *
 * @author LILU
 * @since 2024-11-15
 */
@Service
public class AkApplicationJobServiceImpl extends ServiceImpl<AkApplicationJobMapper, AkApplicationJob> implements IAkApplicationJobService {

    @Resource
    private ClientJobManager clientJobManager;

    @Override
    public void init(List<JobInfo> jobInfoList, AkApplication akApplication) {
        if (jobInfoList == null || jobInfoList.isEmpty()) {
            return;
        }
        for (JobInfo jobName : jobInfoList) {
            AkApplicationJob akApplicationJob = new AkApplicationJob();
            akApplicationJob.setId(CommonUtil.generateUUID());
            akApplicationJob.setApplicationId(akApplication.getId());
            akApplicationJob.setApplicationName(akApplication.getApplicationName());
            akApplicationJob.setBeanName(jobName.getBeanName());
            akApplicationJob.setCronStr(jobName.getCronStr());
            akApplicationJob.setName(jobName.getName());
            akApplicationJob.setCreateTime(LocalDateTime.now());
            akApplicationJob.setStatus(0);
            akApplicationJob.setExecutiveStrategy(4);
            akApplicationJob.setNamespaceId(akApplication.getNamespaceId());
            try {
                this.baseMapper.insert(akApplicationJob);
            } catch (DuplicateKeyException e) {
                // 已经存在，不需要处理
                continue;
            }
        }

    }

    @Override
    public AkApplicationJob updateByDTO(JobUpdateDTO jobUpdateDTO) {
        AkApplicationJob akApplicationJob = this.baseMapper.selectById(jobUpdateDTO.getId());
        if (akApplicationJob == null) {
            new AkException("修改失败,任务已不存在，请刷新后重试");
        }
        BeanUtils.copyProperties(jobUpdateDTO, akApplicationJob);
        this.baseMapper.updateById(akApplicationJob);
        return akApplicationJob;
    }

    @Override
    public List<AkApplicationJob> getListByStatus(Integer status) {
        LambdaQueryWrapper<AkApplicationJob> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(AkApplicationJob::getStatus, status);
        lambdaQueryWrapper.orderByDesc(AkApplicationJob::getCreateTime);
        return this.baseMapper.selectList(lambdaQueryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean start(String id) {
        AkApplicationJob akApplicationJob = this.baseMapper.selectById(id);
        if (akApplicationJob == null) {
            throw new AkException("启动失败,任务已不存在，请刷新后重试");
        }
        if (!StringUtils.hasText(akApplicationJob.getCronStr()) || !CronUtils.isValidExpression(akApplicationJob.getCronStr())) {
            throw new AkException("启动失败,无效的cron表达式");
        }
        LambdaUpdateWrapper<AkApplicationJob> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(AkApplicationJob::getId, id);
        lambdaUpdateWrapper.isNotNull(AkApplicationJob::getCronStr);
        lambdaUpdateWrapper.set(AkApplicationJob::getStatus, 1);
        int update = this.baseMapper.update(null, lambdaUpdateWrapper);
        boolean b = update == 1;
        if (b) {
            try {
                clientJobManager.addDynamicJob(akApplicationJob);
            } catch (Exception e) {
                log.error(e.getMessage(),e);
                throw new AkException("启动失败,请刷新后重试");
            }
        }
        return b;
    }

    @Override
    public Boolean close(String id) {
        AkApplicationJob akApplicationJob = this.baseMapper.selectById(id);
        if (akApplicationJob == null) {
            new AkException("关闭失败,任务已不存在，请刷新后重试");
        }
        LambdaUpdateWrapper<AkApplicationJob> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(AkApplicationJob::getId, id);
        lambdaUpdateWrapper.set(AkApplicationJob::getStatus, 0);
        int update = this.baseMapper.update(null, lambdaUpdateWrapper);
        try {
            clientJobManager.deleteDynamicJob(akApplicationJob);
        } catch (Exception e) {
            throw new AkException("操作失败：" + e.getMessage());
        }
        return update == 1;
    }

    @Override
    public AkPageable<AkApplicationJob> pageList(String applicationId, JobListDTO jobUpdateDTO) {
        PageHelper.startPage(jobUpdateDTO.getStart(), jobUpdateDTO.getLimit());
        List<AkApplicationJob> applicationJobs = this.baseMapper.infoList(applicationId,jobUpdateDTO);
        return AkPageableUtils.create(applicationJobs);
    }

    @Override
    public Integer delByApplicationId(String applicationId) {
        LambdaQueryWrapper<AkApplicationJob> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(AkApplicationJob::getApplicationId, applicationId);
        List<AkApplicationJob> applicationJobs = baseMapper.selectList(lambdaQueryWrapper);
        for (AkApplicationJob applicationJob : applicationJobs) {
            if (applicationJob.getStatus() == 0) {
                continue;
            }
            try {
                // 关闭定时任务
                clientJobManager.deleteDynamicJob(applicationJob);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        int i = this.baseMapper.delete(lambdaQueryWrapper);
        return i;
    }
}
